import pygame
import sys
from pygame.locals import *
import traceback
from random import *

# 导入自定义模块
from commonModule import loadImage
import enemy
import myplane
import bullet
import supply

# 初始化
pygame.init()
pygame.mixer.init()


# 导入背景图片
bg_image = "./images/background.png"

# 导入音乐与音效
game_music = "./sound/game_music.ogg"
enemy3_flying_sound = pygame.mixer.Sound("./sound/enemy3_flying.wav")
enemy1_down_sound = pygame.mixer.Sound("./sound/enemy1_down.wav")
enemy2_down_sound = pygame.mixer.Sound("./sound/enemy2_down.wav")
enemy3_down_sound = pygame.mixer.Sound("./sound/enemy3_down.wav")
supply_sound = pygame.mixer.Sound("./sound/supply.wav")
get_bomb_sound = pygame.mixer.Sound("./sound/get_bomb.wav")
get_bullet_sound = pygame.mixer.Sound("./sound/get_bullet.wav")
upgrade_sound = pygame.mixer.Sound("./sound/upgrade.wav")

# 初始设置
bg_size = width, height = 480, 700
screen = pygame.display.set_mode(bg_size)
pygame.display.set_caption("飞机大战")

# 加载背景图
background = pygame.image.load(bg_image).convert_alpha()

# 播放背景音乐
pygame.mixer.music.load(game_music)
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.play(-1)


# 添加敌机方法
def add_small_enemies(group1, group2, num):
    for i in range(num):
        small_enemy = enemy.SmallEnemy(bg_size)
        group1.add(small_enemy)
        group2.add(small_enemy)


def add_mid_enemies(group1, group2, num):
    for i in range(num):
        mid_enemy = enemy.MidEnemy(bg_size)
        group1.add(mid_enemy)
        group2.add(mid_enemy)


def add_big_enemies(group1, group2, num):
    for i in range(num):
        big_enemy = enemy.BigEnemy(bg_size)
        group1.add(big_enemy)
        group2.add(big_enemy)

# 提升敌机速度


def inc_speed(target, speed):
    for each in target:
        each.speed += speed


def main():
    clock = pygame.time.Clock()
    # 得到我方飞机的实例类
    me = myplane.MyPlane(bg_size)

    # 碰撞检测组
    enemies = pygame.sprite.Group()
    # 生成小，中，大敌机列表
    small_enemies = pygame.sprite.Group()
    big_enemies = pygame.sprite.Group()
    mid_enemies = pygame.sprite.Group()
    add_small_enemies(small_enemies, enemies, 15)
    add_mid_enemies(mid_enemies, enemies, 4)
    add_big_enemies(big_enemies, enemies, 2)

    # 飞机撞毁切换索引
    me_destore_index = 0
    e1_destore_index = 0
    e2_destore_index = 0
    e3_destore_index = 0

    # 定义节流阀延迟帧率
    delay = 100

    # 生成子弹
    bullets = []
    BULLET_NUM = 4
    for i in range(BULLET_NUM):
        bulletObj = bullet.Bullet1(me.rect.midtop)
        bullets.append(bulletObj)
    bullet_index = 0

    # 预定超级子弹
    bullet2 = []
    DOUBLE_NUM = 8
    bullet2_index = 0
    bullet2_start1_pos = (me.rect.centerx-33, me.rect.centery)
    bullet2_start2_pos = ((me.rect.centerx+30, me.rect.centery))
    for each in range(int(DOUBLE_NUM / 2)):
        bullet2.append(bullet.Bullet2(bullet2_start1_pos))
        bullet2.append(bullet.Bullet2(bullet2_start2_pos))
    # 判断是否生成超级子弹
    is_bullet2 = False
    # 触发超级子弹事件
    MY_BULLET_END = USEREVENT + 1

    # 预定义颜色生成血槽
    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)

    # 携带炸弹
    bomb_font = pygame.font.Font("./font/font.ttf", 48)
    bomb_num = 3
    bomb_image = loadImage("bomb.png")
    bomb_rect = bomb_image.get_rect()
    bomb_rect.left, bomb_rect.bottom = 10, height

    # 30秒生成一次补给
    bomb_supplay = supply.BombSupplay(bg_size)
    bullet_supplay = supply.BulletSupplay(bg_size)
    SUPPLY_ITEM = USEREVENT
    pygame.time.set_timer(SUPPLY_ITEM, 30 * 1000)

    # 统计分数
    score = 0
    score_font = pygame.font.Font("./font/font.ttf", 36)

    # 提升级别
    leval = 1

    # 生命条数
    life_num = 3
    # 记录生命图片
    life_image = loadImage("life.png")
    life_rect = life_image.get_rect()

    # 退出无敌事件
    QUIT_INV = USEREVENT + 2

    # 导入暂停图标
    pause_nor = loadImage("pause_nor.png")
    pause_pressed = loadImage("pause_pressed.png")
    resume_nor = loadImage("resume_nor.png")
    resume_pressed = loadImage("resume_pressed.png")
    pause_rect = pause_nor.get_rect()
    pause_rect.right = width - 10
    pause_rect.top = 10
    # pause 是否暂停
    pause = False
    pause_image = pause_nor

    # 预定义游戏结束画面
    best_font = pygame.font.Font("./font/font.ttf", 40)
    your_score_font = pygame.font.Font("./font/font.ttf", 46)
    gameover_img = loadImage("gameover.png")
    again_img = loadImage("again.png")
    gameover_rect = gameover_img.get_rect()
    again_rect = again_img.get_rect()
    gameover_rect.centerx = width / 2
    gameover_rect.bottom = height - 120
    again_rect.centerx = width / 2
    again_rect.bottom = height - 170

    # 定义判断显示我方飞机的第二张图片
    show_image = False
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

            # 随机发送补给
            elif event.type == SUPPLY_ITEM:
                supply_sound.play()
                if choice([True, False]):
                    bomb_supplay.reset()
                else:
                    bullet_supplay.reset()

            # 释放全屏炸弹
            elif event.type == KEYDOWN:
                if event.key == K_SPACE:
                    if bomb_num:
                        bomb_num -= 1
                        for each in enemies:
                            if each.rect.bottom >= 0:
                                each.active = False

            # 结束超级子弹
            elif event.type == MY_BULLET_END:
                pygame.time.set_timer(MY_BULLET_END, 0)
                is_bullet2 = False
                for each in bullet2:
                    each.active = False
            # 退出无敌状态
            elif event.type == QUIT_INV:
                pygame.time.set_timer(QUIT_INV, 0)
                me.invincible = False
            elif event.type == MOUSEBUTTONDOWN:
                if event.button == 1 and pause_rect.collidepoint(event.pos):
                    pause = not pause
                    if pause:
                        pygame.mixer.music.pause()
                        pygame.mixer.pause()
                        pygame.time.set_timer(SUPPLY_ITEM, 0)
                        pause_image = resume_nor
                    else:
                        pygame.mixer.music.unpause()
                        pygame.mixer.unpause()
                        pygame.time.set_timer(SUPPLY_ITEM, 30 * 1000)
                        pause_image = pause_nor
                if event.button == 1 and again_rect.collidepoint(event.pos):
                    main()
                if event.button == 1 and gameover_rect.collidepoint(event.pos):
                    pygame.quit()
                    sys.exit()

                    # 鼠标悬停在暂停按钮上
            elif event.type == MOUSEMOTION:
                if pause_rect.collidepoint(event.pos):
                    if pause:
                        pause_image = resume_pressed
                    else:
                        pause_image = pause_pressed
                else:
                    if pause:
                        pause_image = resume_nor
                    else:
                        pause_image = pause_nor
        # 绘制背景
        screen.blit(background, (0, 0))

        if life_num and not pause:
            # 难度提升
            if leval == 1 and score > 50000:
                leval = 2
                # 播放级别提升音乐
                upgrade_sound.play()
                # 条件3架小型敌机，2架中型敌机,一架大型机
                add_small_enemies(small_enemies, enemies, 3)
                add_mid_enemies(mid_enemies, enemies, 2)
                add_big_enemies(big_enemies, enemies, 1)
                # 增加小型敌机速度
                inc_speed(small_enemies, 1)

            elif leval == 2 and score > 300000:
                leval = 3
                # 播放级别提升音乐
                upgrade_sound.play()
                # 条件5架小型敌机，3架中型敌机,2架大型机
                add_small_enemies(small_enemies, enemies, 5)
                add_mid_enemies(mid_enemies, enemies, 3)
                add_big_enemies(big_enemies, enemies, 2)
                # 增加小型敌机速度
                inc_speed(small_enemies, 1)

            elif leval == 3 and score == 600000:
                leval = 4
                # 播放级别提升音乐
                upgrade_sound.play()
                # 条件5架小型敌机，3架中型敌机,2架大型机
                add_small_enemies(small_enemies, enemies, 5)
                add_mid_enemies(mid_enemies, enemies, 3)
                add_big_enemies(big_enemies, enemies, 2)
                # 增加小型敌机速度
                inc_speed(small_enemies, 1)

            elif leval == 4 and score == 1000000:
                leval = 5
                # 播放级别提升音乐
                upgrade_sound.play()
                # 条件5架小型敌机，3架中型敌机,2架大型机
                add_small_enemies(small_enemies, enemies, 5)
                add_mid_enemies(mid_enemies, enemies, 3)
                add_big_enemies(big_enemies, enemies, 2)
                # 增加小型敌机速度
                inc_speed(small_enemies, 1)

            # 得到事件队列字典
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_UP] or key_pressed[K_w]:
                me.moveUp()
            elif key_pressed[K_DOWN] or key_pressed[K_s]:
                me.moveDown()
            elif key_pressed[K_LEFT] or key_pressed[K_a]:
                me.moveLeft()
            elif key_pressed[K_RIGHT] or key_pressed[K_d]:
                me.moveRight()

            # 判断是否获的补给
            if bomb_supplay.active:
                bomb_supplay.move()
                screen.blit(bomb_supplay.image, bomb_supplay.rect)
                if pygame.sprite.collide_mask(me, bomb_supplay):
                    get_bomb_sound.play()
                    if bomb_num < 3:
                        bomb_num += 1
                    bomb_supplay.active = False

            # 获得超级子弹补给
            if bullet_supplay.active:
                bullet_supplay.move()
                screen.blit(bullet_supplay.image, bullet_supplay.rect)
                if pygame.sprite.collide_mask(me, bullet_supplay):
                    get_bullet_sound.play()
                    bullet_supplay.active = False
                    is_bullet2 = True
                    pygame.time.set_timer(MY_BULLET_END, 18 * 1000)

            # 碰撞检测
            enemies_down = pygame.sprite.spritecollide(
                me, enemies, False, pygame.sprite.collide_mask)
            # 重生时有几秒无敌状态
            if enemies_down and not me.invincible:
                me.active = False
                for each_down in enemies_down:
                    each_down.active = False

            # 发射子弹
            if not(delay % 10):
                if is_bullet2:
                    bullet_list = bullet2
                    bullet2_start1_pos = (me.rect.centerx-33, me.rect.centery)
                    bullet2_start2_pos = (
                        (me.rect.centerx+30, me.rect.centery))
                    bullet2[bullet2_index].reset(bullet2_start1_pos)
                    bullet2[bullet2_index + 1].reset(bullet2_start2_pos)
                    bullet2_index = (bullet2_index + 2) % DOUBLE_NUM
                else:
                    bullet_list = bullets
                    bullets[bullet_index].reset(me.rect.midtop)
                    bullet_index = (bullet_index + 1) % 4

            for each in bullet_list:
                each.move()
                if each.active:
                    screen.blit(each.image, each.rect)
                    enemy_hit = pygame.sprite.spritecollide(
                        each, enemies, False, pygame.sprite.collide_mask)
                    # 子弹是否击中敌机
                    if enemy_hit:
                        each.active = False
                        for e in enemy_hit:
                            # 如果是大型敌机或者中型敌机血量为0时才被击毁
                            if e in mid_enemies or e in big_enemies:
                                e.energy -= 1
                                e.hit = True
                                if not (e.energy):
                                    e.active = False
                            else:
                                e.active = False

            # 绘制大型敌机
            for each in big_enemies:
                each.move()
                if each.active:
                    # 绘制血槽
                    pygame.draw.line(screen, BLACK, (each.rect.left,
                                                     each.rect.top - 5), (each.rect.right, each.rect.top-5), 2)
                    energy_ratio = each.energy / enemy.BigEnemy.energy
                    if energy_ratio > 0.2:
                        energy_color = GREEN
                    else:
                        energy_color = RED
                    pygame.draw.line(screen, energy_color, (each.rect.left,
                                                            each.rect.top - 5), (each.rect.left + each.rect.width*energy_ratio, each.rect.top-5), 2)

                    # 当大型敌机要出现了播放音效
                    if each.rect.bottom == -50:
                        enemy3_flying_sound.play(-1)
                    if each.hit:
                        screen.blit(each.hit_image, each.rect)
                        each.hit = False
                    else:
                        if show_image:
                            screen.blit(each.image2, each.rect)
                        else:
                            screen.blit(each.image, each.rect)
                else:
                    enemy3_flying_sound.stop()
                    # 延迟帧率切换图片
                    if not(delay % 3):
                        if e3_destore_index == 0:
                            enemy3_down_sound.play()
                        image = each.destore_images[e3_destore_index]
                        screen.blit(image, each.rect)
                        e3_destore_index = (e3_destore_index+1) % 4
                        if e3_destore_index == 0:
                            score += 10000
                            each.reset()

            # 绘制中型敌机
            for each in mid_enemies:
                each.move()
                if each.active:
                    # 绘制血槽
                    pygame.draw.line(screen, BLACK, (each.rect.left,
                                                     each.rect.top - 5), (each.rect.right, each.rect.top-5), 2)
                    energy_ratio = each.energy / enemy.BigEnemy.energy
                    if energy_ratio > 0.2:
                        energy_color = GREEN
                    else:
                        energy_color = RED
                    pygame.draw.line(screen, energy_color, (each.rect.left,
                                                            each.rect.top - 5), (each.rect.left + each.rect.width*energy_ratio, each.rect.top-5), 2)
                    if each.hit:
                        screen.blit(each.hit_image, each.rect)
                        each.hit = False
                    else:
                        screen.blit(each.image, each.rect)
                else:
                    # 延迟帧率切换图片
                    if not(delay % 3):
                        if e2_destore_index == 0:
                            enemy2_down_sound.play()
                        image = each.destore_images[e2_destore_index]
                        screen.blit(image, each.rect)
                        e2_destore_index = (e2_destore_index+1) % 4
                        if e2_destore_index == 0:
                            score += 6000
                            each.reset()

            # 绘制小型敌机
            for each in small_enemies:
                each.move()
                if each.active:
                    screen.blit(each.image, each.rect)
                else:
                    # 延迟帧率切换图片
                    if not(delay % 3):
                        if e1_destore_index == 0:
                            enemy1_down_sound.play()
                        image = each.destore_images[e1_destore_index]
                        screen.blit(image, each.rect)
                        e1_destore_index = (e1_destore_index+1) % 4
                        if e1_destore_index == 0:
                            score += 1000
                            each.reset()

            # 绘制我方飞机
            if me.active:
                if show_image:
                    screen.blit(me.image2, me.rect)
                else:
                    screen.blit(me.image, me.rect)
            else:
                # 延迟帧率切换图片
                if not(delay % 3):
                    image = me.destore_images[me_destore_index]
                    screen.blit(image, me.rect)
                    me_destore_index = (me_destore_index+1) % 4
                    if e1_destore_index == 0:
                        life_num -= 1
                        pygame.time.set_timer(QUIT_INV, 3 * 1000)
                        me.reset()
            # 绘制携带炸弹
            screen.blit(bomb_image, bomb_rect)
            bomb_text = bomb_font.render("×%s" % bomb_num, True, WHITE)
            bomb_text_rect = bomb_text.get_rect()
            bomb_text_rect.left = 80
            bomb_text_rect.bottom = height
            screen.blit(bomb_text, bomb_text_rect)

            for i in range(life_num):
                life_rect.right = width - life_rect.width * i
                life_rect.bottom = height
                screen.blit(life_image, life_rect)
            show_image = not(delay % 5)
            delay -= 1
            if not delay:
                delay = 100
        if life_num:
            score_text = score_font.render("Score : %s" % score, True, WHITE)
            score_rect = score_text.get_rect()
            score_rect.left = 10
            score_rect.top = 0
            screen.blit(score_text, score_rect)

            # 绘制暂停图
            screen.blit(pause_image, pause_rect)
        elif not life_num:
            # 绘制结束画面
            with open("record.txt", encoding="utf-8") as f:
                try:
                    total_score = int(str(f.read()))
                except:
                    with open("record.txt", 'w', encoding="utf-8") as f1:
                        f1.write(str(score))
                        total_score = score
            if score > total_score:
                total_score = score
                with open("record.txt", 'w', encoding="utf-8") as f1:
                    f1.write(str(total_score))
            best_text = best_font.render(
                "Best : %s" % total_score, True, WHITE)
            your_score_text = your_score_font.render(
                "Your Score", True, WHITE)
            end_score_text = your_score_font.render(
                str(score), True, WHITE)
            end_score_rect = end_score_text.get_rect()
            end_score_rect.centerx = width / 2
            end_score_rect.centery = height / 2 + 20
            your_score_rect = your_score_text.get_rect()
            your_score_rect.center = width / 2, height / 2 - 20
            screen.blit(best_text, (40, 40))
            screen.blit(your_score_text, your_score_rect)
            screen.blit(end_score_text, end_score_rect)
            screen.blit(again_img, again_rect)
            screen.blit(gameover_img, gameover_rect)

        # 绘制得分
        pygame.display.flip()
        clock.tick(60)


if __name__ == "__main__":
    try:
        main()
    except SystemExit:
        pass
    except:
        traceback.print_exc()
        pygame.quit()
        input()
